package com.pro.common.login.service;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.pro.common.api.CommonConst;
import com.pro.common.api.enums.EnumLoginEntrance;
import com.pro.common.api.enums.EnumSysRole;
import com.pro.common.api.exception.BusinessException;
import com.pro.common.api.model.ILoginInfo;
import com.pro.common.api.model.ILoginLog;
import com.pro.common.api.model.request.ILoginRequest;
import com.pro.common.api.model.request.LoginRequest;
import com.pro.common.api.sitecontent.intf.AuthRoleFeignClient;
import com.pro.common.api.sitecontent.model.request.AuthRoleGetPathRequest;
import com.pro.common.api.user.model.IUser;
import com.pro.common.jwt.IJwtClaimsService;
import com.pro.common.jwt.login.LoginInfoDTO;
import com.pro.common.login.model.request.AdminLoginRequest;
import com.pro.common.modules.service.dependencies.util.IPUtils;
import com.pro.common.jwt.AccessTokenJwt;
import com.pro.common.service.service.EnumAuthDict;
import com.pro.framework.api.cache.ICacheManagerCenter;
import com.pro.framework.api.util.AssertUtil;
import com.pro.framework.api.util.PasswordUtils;
import com.pro.framework.api.util.StrUtils;
import com.pro.framework.cache.CacheManagerCenterRedis;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Slf4j
@Service
public class CommonLoginService<T extends ILoginInfo> {
    @Autowired
    private IJwtClaimsService claimsService;
    //    @Autowired
//    private ISysMsgClient sysMsgService;
    @Autowired
    private ICacheManagerCenter cacheManagerCenter;
    @Autowired
    private BaseLoginInfoService<? extends BaseMapper<T>, T> loginInfoService;
    @Autowired
    private AuthRoleFeignClient authRoleFeignClient;
    @Autowired
    private CacheManagerCenterRedis cacheManagerCenterRedis;


    @Transactional(rollbackFor = Exception.class)
    public AccessTokenJwt login(ILoginRequest request) {
        T loginInfo = loginInfoService.getLoginInfo(request);
        if (loginInfo == null) {
            throw new BusinessException("用户不存在_", request.getUsername());
        }
        AssertUtil.notEmpty(loginInfo, "用户不存在_", request.getUsername());
        AssertUtil.isTrue(loginInfo.getEnabled(), "区域限制_无法登陆");

        // 密码生成器
        if (!loginInfo.getPassword().equals(PasswordUtils.encrypt_Password(request.getPassword()))) {
            throw new BusinessException("密码错误");
        }

        loginInfoService.doAfterLogin(loginInfo);
        // 返回登录token
        AccessTokenJwt accessTokenJwt = this.generateToken(loginInfo);
        cacheManagerCenterRedis.put("userLoginLimit", StrUtils.md5(accessTokenJwt.getAccessToken()), loginInfo.getId(), 14L, TimeUnit.DAYS);
        return accessTokenJwt;

    }

    public AccessTokenJwt generateToken(T loginInfo) {
        LoginInfoDTO loginInfoDTO = new LoginInfoDTO();
        loginInfoDTO.setId(loginInfo.getId());
        loginInfoDTO.setSysRole(loginInfo.getSysRole());
        Set<String> permissionPaths = null;
        Set<String> permissionPathsPrefix = null;
        Set<Long> roleIds = Arrays.stream(loginInfo.getRoleIds().split(",")).filter(s -> !s.isEmpty()).map(Long::valueOf).collect(Collectors.toSet());
        permissionPaths = authRoleFeignClient.getPath(new AuthRoleGetPathRequest(loginInfoDTO.getSysRole(), roleIds));
        permissionPathsPrefix = permissionPaths.stream().filter(p -> p.endsWith("*")).map(u -> u.replaceAll("\\*+$", "")).collect(Collectors.toSet());
        permissionPaths = permissionPaths.stream().filter(p -> !p.endsWith("*")).collect(Collectors.toSet());
        loginInfoDTO.setPermissionPaths(permissionPaths);
        loginInfoDTO.setPermissionPathsPrefix(permissionPathsPrefix);

        cacheManagerCenter.put(CommonConst.CacheKey.LoginInfo, loginInfo.getSysRole().name() + loginInfo.getId(), loginInfoDTO);

        return claimsService.loginToToken(loginInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    public AccessTokenJwt register(String request, String ip, String lang,String smsCode) {
        // 注册
        T loginInfo = loginInfoService.register(request, ip, lang,smsCode);
        // 返回登录token
        return generateToken(loginInfo);
    }

    public T getLoginInfo(Long id) {
        return loginInfoService.getById(id);
    }

    public Boolean getGoogleAuthOpen(LoginRequest request) {
        T loginInfo = loginInfoService.getLoginInfo(request);
        return null != loginInfo && loginInfo.getGoogleAuthOpen();
    }

    @Transactional(rollbackFor = Exception.class)
    public AccessTokenJwt register(HttpServletRequest request, String captchaInner, String requestBody, String smsCode) {
        JSONObject jo = JSONUtil.parseObj(requestBody);
        // 图形验证码
        if (EnumAuthDict.REGISTER_PROPS.getValueCache().contains(",captcha,")) {
            String captcha = jo.getStr("captcha");
            if (StrUtils.isBlank(captcha)) {
                throw new BusinessException("图形验证码不正确");
            } else if (!captcha.equals(captchaInner)) {
                throw new BusinessException("图形验证码不正确");
            }
        }
//        if (EnumAuthDict.REGISTER_PROPS.getValueCache().contains(",smsCode,")) {
//            String codeInput = jo.getStr("smsCode");
//
////            UserMsg request = Mappers.getMapper(UserMapper.class).userToMsgUser(ori);
//            String key = sysMsgService.getMsgKey(jo.toBean(UserMsg.class), EnumSysMsgBusinessCode.REGISTER_CODE.name());
//            String code = (String) cacheManagerCenter.get(CommonConst.CacheKey.SmsCode, key);
//            AssertUtil.isTrue(StrUtil.isNotBlank(code) && code.equals(codeInput), "短信或邮箱验证码不正确");
//        }

        String ip = IPUtils.getIpAddress(request);
        // 返回token
        return this.register(requestBody, ip, LocaleContextHolder.getLocale().toLanguageTag(),smsCode);
    }

    public AccessTokenJwt adminLogin(String paramMap, Long agentId, ILoginInfo loginInfo) {
        AdminLoginRequest params = JSONUtil.toBean(paramMap, AdminLoginRequest.class);
        Long id = params.getId();
        T adminToLoginInfo = loginInfoService.getById(id);
        switch (loginInfoService.getSysRole()){
            case USER -> {
                if (agentId != null && adminToLoginInfo instanceof IUser user) {
                    // 检查代理端权限
                    AssertUtil.isTrue(agentId.equals(user.getAgentId()), "暂无权限");
                }
            }
            case AGENT -> AssertUtil.isTrue(EnumSysRole.ADMIN.equals(loginInfo.getSysRole()), "暂无权限");
            case ADMIN -> throw new BusinessException(403, "暂无权限");
        }
        adminToLoginInfo.setLoginEntrance(EnumLoginEntrance.ADMIN.name());
        return generateToken(adminToLoginInfo);
    }

    public void getActivity(HttpServletRequest request) {
        loginInfoService.getActivity( request);
    }
}
